/* Copyright (c) 2015,2016 Lucky Byte, Inc.
 */
package com.lucky_byte.pay.jar;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.lang.ProcessBuilder.Redirect;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import static org.apache.commons.lang3.StringEscapeUtils.escapeHtml4;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

/**
 * 通过 wkhtmltopdf 转换 PDF
 */
public class WebkitPDF
{
	private static final Logger logger = LogManager.getLogger();

	public static File toPDF(File input_file, String title,
			String encoding, File pdf_file,
			Map<String, String> params) throws IOException {
		List<String> commands = new ArrayList<>();
		commands.add("wkhtmltopdf");

		// 通用选项
		addOptions(commands, "--load-error-handling", "ignore");
//		commands.add("--quiet");
		commands.add("--print-media-type");
		addOptions(commands, "--encoding", encoding);

		// 纸张选项
		addOptions(commands, "--orientation",
				getStringParam(params, "orientation", "Landscape"));
		addOptions(commands, "--title", title);
		addOptions(commands, "--margin-left",
				getStringParam(params, "margin_left", "20"));
		addOptions(commands, "--margin-right",
				getStringParam(params, "margin_right", "15"));
		addOptions(commands, "--margin-top",
				getStringParam(params, "margin_top", "15"));
		addOptions(commands, "--margin-bottom",
				getStringParam(params, "margin_bottom", "15"));
		addOptions(commands, "--page-size",
				getStringParam(params, "paper_size", "A4"));

		// 页眉选项
		String value = getStringParam(params, "header_left", "");
		if (!value.isEmpty()) {
			addOptions(commands, "--header-left", value);
		}
		value = getStringParam(params, "header_center", "");
		if (!value.isEmpty()) {
			addOptions(commands, "--header-center", value);
		}
		value = getStringParam(params, "header_right", "");
		if (!value.isEmpty()) {
			addOptions(commands, "--header-right", value);
		}
		addOptions(commands, "--header-spacing",
				getStringParam(params, "header_spacing", "5"));
		if (getCheckParam(params, "header_line")) {
			commands.add("--header-line");
		}
		addOptions(commands, "--header-font-size", "8");

		// 页脚选项
		value = getStringParam(params, "footer_left", "");
		if (!value.isEmpty()) {
			addOptions(commands, "--footer-left", value);
		}
		value = getStringParam(params, "footer_center", "");
		if (!value.isEmpty()) {
			addOptions(commands, "--footer-center", value);
		}
		value = getStringParam(params, "footer_right", "");
		if (!value.isEmpty()) {
			addOptions(commands, "--footer-right", value);
		}
		addOptions(commands, "--footer-spacing",
				getStringParam(params, "footer_spacing", "5"));
		if (getCheckParam(params, "footer_line")) {
			commands.add("--footer-line");
		}
		addOptions(commands, "--footer-font-size", "8");

		// 定制
		addOptions(commands, "--replace", "vendor", Version.VENDOR);

		String filename = input_file.getName();
		if (filename.endsWith(".html") || filename.endsWith(".htm")) {
			commands.add(input_file.getAbsolutePath());
			return run(commands, pdf_file);
		}
		// 输入文件如果不是 html 文件，则增加一层 html 封装.
		File html_file = wrap(input_file, encoding);
		commands.add(html_file.getAbsolutePath());
		File pdffile = run(commands, pdf_file);
		html_file.delete();
		return pdffile;
	}

	private static void addOptions(List<String> commands,
			String option, String... args) {
		commands.add(option);
		for (String arg : args) {
			commands.add(arg);
		}
	}

	private static String getStringParam(Map<String, String> params,
			String name, String defval) {
		String value = params.get(name);
		if (value == null || value.trim().isEmpty()) {
			value = defval;
		}
		return value;
	}

	private static boolean getCheckParam(Map<String, String> params,
			String name) {
		String value = params.get(name);
		if (value == null) {
			return false;
		}
		if (value.equalsIgnoreCase("on") || value.equalsIgnoreCase("true")) {
			return true;
		}
		return false;
	}

	private static File wrap(File input_file, String encoding)
			throws IOException {
		StringBuilder builder = new StringBuilder();
		builder.append("<html><head>");
		builder.append("<meta charset=\"").append(encoding).append("\">");
		builder.append("</head><body><pre>");
		BufferedReader reader = new BufferedReader(
				new InputStreamReader(
						new FileInputStream(input_file), encoding));
		while (true) {
			String line = reader.readLine();
			if (line == null) {
				break;
			}
			builder.append(escapeHtml4(line)).append("\n");
		}
		reader.close();
		builder.append("</pre></body></html>");

		File html_file = File.createTempFile("ftl-", ".html");
		OutputStreamWriter writer = new OutputStreamWriter(
				new FileOutputStream(html_file), encoding);
		writer.write(builder.toString());
		writer.close();
		return html_file;
	}

	/**
	 * 运行 wkhtmltopdf 命令
	 */
	private static File run(List<String> commands, File pdf_file)
			throws IOException {
		if (pdf_file == null) {
			pdf_file = File.createTempFile("ftl-", ".pdf");
		}
		File parent = pdf_file.getParentFile();
		if (parent != null && !parent.exists()) {
			if (!parent.mkdirs()) {
				logger.error("建立目录[{}]错误.", parent.getPath());
				return null;
			}
		}
		commands.add(pdf_file.getAbsolutePath());

		ProcessBuilder builder = new ProcessBuilder();
		builder.command(commands);
		builder.redirectErrorStream(true);
		builder.redirectOutput(Redirect.PIPE);
		Process process = builder.start();

		if (logger.isDebugEnabled()) {
			InputStream stream = process.getInputStream();
			BufferedReader reader = new BufferedReader(
					new InputStreamReader(stream));
			StringBuilder output = new StringBuilder("PDF 转换日志:\n");
			while (true) {
				String line = reader.readLine();
				if (line == null) {
					break;
				}
				output.append(line).append("\n");
			}
			logger.debug(output.toString());
		}
		return pdf_file;
	}
}
